#!/usr/bin/env python
# -*- coding: utf-8 -*-

################################################################################
## Simplification Wrapper around minidom
## ensure "unicode" manipulation
##
## manatlan
################################################################################
## XmlDoc  wrap DocumentObject
## XmlNode wrap NodeObject
################################################################################

from xml.dom.minidom import parse, parseString
import urllib

def u(s):
    """ return any s as "unicode string" """
    if type(s)==unicode:
        return s
    elif type(s)== str:
        try:
            v=s.decode("utf_8")
        except:
            try:
                v=s.decode("mbcs")
            except:
                try:
                    v=s.decode("cp1252")
                except:
                    raise "u() unicodification error : "+str([s])
        return v
    else:
        return unicode(s)

################################################################################
class XmlDoc(object):
################################################################################
    def __init__(self,file="",xml="",url="",dom=None):
        if file:
            self.__dom = parse(file)
        elif xml:
            self.__dom = parseString(xml)
        elif url:
            f = urllib.urlopen(url)
            data = f.read()
            f.close()   
            self.__dom = parseString(data)
        elif dom:
            self.__dom = dom
        else:
            raise "bad XmlDoc call()"

    def __getDE(self):
        """ recupere la node documentElement (root) du doc """
        return XmlNode(self.__dom.documentElement)
    documentElement=property(__getDE)


    def getAll(self,n):
        """ retourne une liste des xmlNode du nom de "n" de la dom """
        return [XmlNode(i) for i in self.__dom.getElementsByTagName(u(n))]
        
    def createNode(self,n,attrs={}):
        """ cree une xmlNode du nom de "n" avec ses attributs(dict) "attr" si renseigné """
        node=self.__dom.createElement(u(n))
        if attrs:
            for i in attrs:
                nom = u(i)
                val = u(attrs[i])
                node.setAttributeNode(self.__dom.createAttribute(nom)) 
                node.setAttribute(nom,val)
        return XmlNode(node)
        
    def dump(self):
        """ renvoi le contenu xml de la dom """
        self.crunch()
        xml = self.__dom.toprettyxml()
        xml=xml.replace( u"""<?xml version="1.0" ?>""",
                        u"""<?xml version="1.0" encoding="utf-8" ?>""")
        return  xml # en UNICODE !!!
        
    def saveAs(self,name):
        """ enregistre la dom dans le fichier "name" """
        fid = open(name,"w")
        if fid:
            #~ self.__dom.writexml(fid,encoding="utf-8",addindent="\t",newl="\r") # BUGGED !!!
            fid.write( self.dump().encode("utf_8") )
            fid.close()
            
            return True
        return False
        
    def crunch(self,node=None):
        """ supprime les nodes text qui sont vides """
        if not node:
            node = self.__dom.documentElement
            
        aeff=[]
        for i in node.childNodes:
            if i.nodeType == i.TEXT_NODE:
                content = i.data.strip(" \r\n\t")
                if not content:
                    aeff.append(i)
                else:
                    i.data = content
            elif i.nodeType == i.ELEMENT_NODE:
                self.crunch(i)
                
        for i in aeff:
            i.parentNode.removeChild(i)
            


################################################################################
class XmlNode(object):  # renvoi de l'utf8 ;-( ... comme libxml2
################################################################################
    def __getOD(self):
        """ recupere le XmlDoc maitre """
        return XmlDoc(dom = self.__node.ownerDocument)
    ownerDocument=property(__getOD)

    def __getCN(self):
        """ recupere la liste de ses childnodes """
        return [XmlNode(i) for i in self.__node.childNodes]
    childNodes=property(__getCN)

    def __getN(self):
        """ recupere la vrai NODE ;-( """
        return self.__node
    node=property(__getN)

    def __init__(self,node):
        self.__node = node
        
    def getAttr(self,nom):
        """ retourne le contenu de l'attribut "nom" de la node """
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
        return self.__node.getAttribute(u(nom))
        #~ return self.__node.getAttribute(u(nom)).encode("utf_8")
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

    def setAttr(self,nom,val):
        """ retourne le contenu de l'attribut "nom" de la node """
        return self.__node.setAttribute(u(nom),u(val))

    def removeChilds(self):
        """ supprimes les nodes filles"""
        for node in self.__node.childNodes:
            self.__node.removeChild(node)

    def setText(self,val):
        """ màj le contenu texte de la node """
        self.removeChilds()
        t=self.__node.ownerDocument.createTextNode(u(val)) # val en unicode !!!
        self.__node.appendChild(t)

    def getText(self):
        """ recupere le contenu texte de la node """
        rc = u""
        for node in self.__node.childNodes:
            if node.nodeType == node.TEXT_NODE:
                rc = rc + node.data
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
        return rc.strip()
        #~ return rc.strip().encode("utf_8")
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
        
    def appendChild(self,n):
        """ ajoute la xmlNode "n" à la node """
        return XmlNode(self.__node.appendChild(n.__node))
        
    def unlink(self):
        """ supprime la node """
        self.__node.parentNode.removeChild(self.__node)
        del(self)
        
    def getAll(self,n):
        """ retourne une liste des xmlNode du nom de "n" à partir de la node """
        return [XmlNode(i) for i in self.__node.getElementsByTagName(u(n))]             

if __name__ == "__main__":
    x=XmlDoc(xml="<root><a/><a/></root>")
    
    n= x.getAll("a")
    n[0].setText(u"fdés")
    x.saveAs("jo.xml")
    
    x=XmlDoc(file="jo.xml")
    n= x.getAll("a")
    
    q=x.createNode("kàkà",{"jimà":12,u"kà":12.23})
    q.setText(u"àùùù")
    n[0].appendChild(q)
    
    n[1].setText(u"fdés")
    n[1].setAttr("joé","jimà")
    x.saveAs("jo.xml")
    print x.dump().encode("utf_8")
 